﻿// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using AM.Reporting.Utils;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

#endregion

#nullable enable

namespace AM.Reporting.Gauge.Simple.Progress
{
    /// <summary>
    /// SimpleProgressGauge pointer types
    /// </summary>
    public enum SimpleProgressPointerType
    {
        /// <summary>
        /// Full sized pointer
        /// </summary>
        Full,

        /// <summary>
        /// Small pointer
        /// </summary>
        Small
    }

    /// <inheritdoc />
#if !DEBUG
    [DesignTimeVisible(false)]
#endif
    public class SimpleProgressPointer : SimplePointer
    {
        private float smallPointerWidthRatio;

        /// <summary>
        /// Gets or sets the pointer type
        /// </summary>
        public SimpleProgressPointerType Type { get; set; }

        /// <summary>
        /// Gets or sets the small pointer width ratio
        /// </summary>
        public float SmallPointerWidthRatio
        {
            get => smallPointerWidthRatio;
            set
            {
                if (value > 1)
                {
                    smallPointerWidthRatio = 1;
                }
                else if (value < 0)
                {
                    smallPointerWidthRatio = 0;
                }
                else
                {
                    smallPointerWidthRatio = value;
                }
            }
        }

        /// <inheritdoc />
        public SimpleProgressPointer (GaugeObject parent) : base (parent)
        {
            smallPointerWidthRatio = 0.1f;
        }

        internal override void DrawHorz (PaintEventArgs e)
        {
            var g = e.Graphics;
            var pen = e.Cache.GetPen (BorderColor, BorderWidth * e.ScaleX, DashStyle.Solid);

            Left = (Parent.AbsLeft + Parent.Border.Width / 2 + HorizontalOffset) * e.ScaleX;
            Top = (Parent.AbsTop + Parent.Border.Width / 2 + (Parent.Height - Parent.Border.Width) / 2 -
                   (Parent.Height - Parent.Border.Width) * PointerRatio / 2) * e.ScaleY;
            Height = ((Parent.Height - Parent.Border.Width) * PointerRatio) * e.ScaleY;
            Width = (float)((Parent.Width - Parent.Border.Width - HorizontalOffset * 2) *
                (Parent.Value - Parent.Minimum) / (Parent.Maximum - Parent.Minimum) * e.ScaleX);

            if (Type == SimpleProgressPointerType.Small)
            {
                var prntWidth = (Parent.Width - Parent.Border.Width + HorizontalOffset) * e.ScaleX;
                var widthSml = (Parent.Width - Parent.Border.Width - HorizontalOffset * 2) * smallPointerWidthRatio *
                               e.ScaleX;
                var leftSml = Left + Width - prntWidth * smallPointerWidthRatio + widthSml / 2;

                if (leftSml >= Left && leftSml + widthSml < Left + prntWidth)
                {
                    Left = leftSml;
                }
                else if (leftSml + widthSml >= Left + prntWidth)
                {
                    Left += prntWidth - widthSml;
                }

                Width = widthSml;
            }

            var brush = Fill.CreateBrush (new RectangleF (Left, Top, Width, Height), e.ScaleX, e.ScaleY);
            g.FillAndDrawRectangle (pen, brush, Left, Top, Width, Height);
        }

        internal override void DrawVert (PaintEventArgs e)
        {
            var g = e.Graphics;
            var pen = e.Cache.GetPen (BorderColor, BorderWidth * e.ScaleY, DashStyle.Solid);

            Width = ((Parent.Width - Parent.Border.Width) * PointerRatio) * e.ScaleX;
            Height = (float)((Parent.Height - Parent.Border.Width - HorizontalOffset * 2) *
                (Parent.Value - Parent.Minimum) / (Parent.Maximum - Parent.Minimum) * e.ScaleY);
            Left = (Parent.AbsLeft + Parent.Border.Width / 2 + (Parent.Width - Parent.Border.Width) / 2 -
                    (Parent.Width - Parent.Border.Width) * PointerRatio / 2) * e.ScaleX;
            Top = (Parent.AbsTop + Parent.Border.Width / 2 + Parent.Height - Parent.Border.Width) * e.ScaleY - Height;

            if (Type == SimpleProgressPointerType.Small)
            {
                var prntTop = (Parent.AbsTop + Parent.Border.Width / 2) * e.ScaleY;
                var prntHeight = (Parent.Height - Parent.Border.Width) * e.ScaleY;
                var heightSml = (Parent.Height - Parent.Border.Width) * smallPointerWidthRatio * e.ScaleY;
                var topSml = Top - heightSml / 2;

                if (topSml + heightSml > prntTop + prntHeight)
                {
                    Top = prntTop + prntHeight - heightSml;
                }
                else if (topSml < prntTop)
                {
                    Top = prntTop;
                }
                else
                {
                    Top = topSml;
                }

                Height = heightSml;
            }

            var brush = Fill.CreateBrush (new RectangleF (Left, Top, Width, Height), e.ScaleX, e.ScaleY);
            g.FillAndDrawRectangle (pen, brush, Left, Top, Width, Height);
        }

        /// <inheritdoc />
        public override void Assign (GaugePointer src)
        {
            base.Assign (src);
            var s = src as SimpleProgressPointer;
            Type = s.Type;
            SmallPointerWidthRatio = s.SmallPointerWidthRatio;
        }

        /// <inheritdoc />
        public override void Serialize (ReportWriter writer, string prefix, GaugePointer diff)
        {
            base.Serialize (writer, prefix, diff);

            var dc = diff as SimpleProgressPointer;
            if (Type != dc.Type)
            {
                writer.WriteValue (prefix + ".Type", Type);
            }

            if (SmallPointerWidthRatio != dc.SmallPointerWidthRatio)
            {
                writer.WriteValue (prefix + ".SmallPointerWidthRatio", SmallPointerWidthRatio);
            }
        }
    }
}
